package org.budo.redis.jdbc.driver.executor.jedis;

import java.util.List;
import java.util.Map;
import java.util.Set;

import org.budo.jdbc.driver.JdbcUrl;
import org.budo.redis.jdbc.driver.executor.AbstractRedisStatementExecutor;
import org.budo.support.lang.util.StringUtil;

import lombok.NoArgsConstructor;
import redis.clients.jedis.BinaryClient.LIST_POSITION;
import redis.clients.jedis.Jedis;

/**
 * @author lmw
 */
@NoArgsConstructor
public class BudoJedisRedisStatementExecutor extends AbstractRedisStatementExecutor {
    private Jedis jedis;

    public BudoJedisRedisStatementExecutor(JdbcUrl jdbcUrl, String password) {
        this.setJdbcUrl(jdbcUrl);
        this.setPassword(password);
    }

    @Override
    public Long append(byte[] key, byte[] value) {
        return this.getJedis().append(key, value);
    }

    @Override
    public void close() {
        this.getJedis().close();
    }

    @Override
    public Long decr(byte[] key) {
        return this.getJedis().decr(key);
    }

    @Override
    public Long decrBy(byte[] key, Long value) {
        return this.getJedis().decrBy(key, value);
    }

    @Override
    public Long del(byte[][] keys) {
        return this.getJedis().del(keys);
    }

    @Override
    public Boolean exists(byte[] key) {
        return this.getJedis().exists(key);
    }

    @Override
    public Long expire(byte[] key, Integer expireIn) {
        return this.getJedis().expire(key, expireIn);
    }

    @Override
    public Long expireAt(byte[] key, Long unixTime) {
        return this.getJedis().expireAt(key, unixTime);
    }

    @Override
    public byte[] get(byte[] key) {
        return this.getJedis().get(key);
    }

    public Jedis getJedis() {
        if (null != this.jedis) {
            return this.jedis;
        }

        synchronized (BudoJedisRedisStatementExecutor.class) {
            if (null != this.jedis) {
                return this.jedis;
            }

            return this.jedis = this.initJedis();
        }
    }

    private Jedis initJedis() {
        try {
            Jedis jedis = new Jedis(this.getJdbcUrl().getHost(), this.getJdbcUrl().getPort());

            if (!StringUtil.isEmpty(this.getPassword())) {
                jedis.auth(this.getPassword());
            }

            jedis.select(this.getJdbcUrl().getCatalogAsInteger());
            return jedis;
        } catch (Throwable e) {
            throw new RuntimeException("#98 this=" + this + ", e=" + e, e);
        }
    }

    @Override
    public byte[] getrange(byte[] key, Long from, Long to) {
        return this.getJedis().getrange(key, from, to);
    }

    @Override
    public byte[] getSet(byte[] key, byte[] value) {
        return this.getJedis().getSet(key, value);
    }

    @Override
    public Long hdel(byte[] key, byte[][] fields) {
        return this.getJedis().hdel(key, fields);
    }

    @Override
    public Boolean hexists(byte[] key, byte[] field) {
        return this.getJedis().hexists(key, field);
    }

    @Override
    public byte[] hget(byte[] key, byte[] field) {
        return this.getJedis().hget(key, field);
    }

    @Override
    public Map<byte[], byte[]> hgetAll(byte[] key) {
        return this.getJedis().hgetAll(key);
    }

    @Override
    public Long hincrBy(byte[] key, byte[] field, Long value) {
        return this.getJedis().hincrBy(key, field, value);
    }

    @Override
    public Double hincrByFloat(byte[] key, byte[] field, Double value) {
        return this.getJedis().hincrByFloat(key, field, value);
    }

    @Override
    public byte[][] hkeys(byte[] key) {
        Set<byte[]> hkeys = this.getJedis().hkeys(key);
        return hkeys.toArray(new byte[hkeys.size()][]);
    }

    @Override
    public Long hlen(byte[] key) {
        return this.getJedis().hlen(key);
    }

    @Override
    public byte[][] hmget(byte[] key, byte[][] fields) {
        List<byte[]> hmget = this.getJedis().hmget(key, fields);
        return hmget.toArray(new byte[hmget.size()][]);
    }

    @Override
    public String hmset(byte[] key, Map<byte[], byte[]> map) {
        return this.getJedis().hmset(key, map);
    }

    @Override
    public Long hset(byte[] key, byte[] field, byte[] value) {
        return this.getJedis().hset(key, field, value);
    }

    @Override
    public Long hsetnx(byte[] key, byte[] field, byte[] value) {
        return this.getJedis().hsetnx(key, field, value);
    }

    @Override
    public byte[][] hvals(byte[] key) {
        List<byte[]> hvals = this.getJedis().hvals(key);
        return hvals.toArray(new byte[hvals.size()][]);
    }

    @Override
    public Long incr(byte[] key) {
        return this.getJedis().incr(key);
    }

    @Override
    public Long incrBy(byte[] key, Long value) {
        return this.getJedis().incrBy(key, value);
    }

    @Override
    public Double incrByFloat(byte[] key, Double value) {
        return this.getJedis().incrByFloat(key, value);
    }

    @Override
    public byte[][] keys(byte[] pattern) {
        Set<byte[]> keys = this.getJedis().keys(pattern);
        return keys.toArray(new byte[keys.size()][]);
    }

    @Override
    public byte[] lindex(byte[] key, Long index) {
        return this.getJedis().lindex(key, index);
    }

    @Override
    public Long linsert(byte[] key, byte[] position, byte[] pivot, byte[] value) {
        LIST_POSITION where = LIST_POSITION.valueOf(new String(position));
        return this.getJedis().linsert(key, where, pivot, value);
    }

    @Override
    public Long llen(byte[] key) {
        return this.getJedis().llen(key);
    }

    @Override
    public byte[] lpop(byte[] key) {
        return this.getJedis().lpop(key);
    }

    @Override
    public Long lpush(byte[] key, byte[][] values) {
        return this.getJedis().lpush(key, values);
    }

    @Override
    public Long lpushx(byte[] key, byte[] value) {
        return this.getJedis().lpushx(key, value);
    }

    @Override
    public byte[][] lrange(byte[] key, Long start, Long end) {
        List<byte[]> lrange = this.getJedis().lrange(key, start, end);
        return lrange.toArray(new byte[lrange.size()][]);
    }

    @Override
    public Long lrem(byte[] key, Long count, byte[] value) {
        return this.getJedis().lrem(key, count, value);
    }

    @Override
    public String lset(byte[] key, Long index, byte[] value) {
        return this.getJedis().lset(key, index, value);
    }

    @Override
    public String ltrim(byte[] key, Long start, Long end) {
        return this.getJedis().ltrim(key, start, end);
    }

    @Override
    public byte[][] mget(byte[][] keys) {
        List<byte[]> mget = this.getJedis().mget(keys);
        return mget.toArray(new byte[mget.size()][]);
    }

    @Override
    public Long move(byte[] key, Integer dbIndex) {
        return this.getJedis().move(key, dbIndex);
    }

    @Override
    public String mset(byte[][] keyValues) {
        return this.getJedis().mset(keyValues);
    }

    @Override
    public Long msetnx(byte[][] keyValues) {
        return this.getJedis().msetnx(keyValues);
    }

    @Override
    public Long persist(byte[] key) {
        return this.getJedis().persist(key);
    }

    @Override
    public Long pexpire(byte[] key, Long milliSeconds) {
        return this.getJedis().pexpire(key, milliSeconds);
    }

    @Override
    public Long pexpireAt(byte[] key, Long milliSecondsTimestamp) {
        return this.getJedis().pexpireAt(key, milliSecondsTimestamp);
    }

    @Override
    public String psetex(byte[] key, Long milliSeconds, byte[] value) {
        return this.getJedis().psetex(key, milliSeconds, value);
    }

    @Override
    public Long pttl(byte[] key) {
        return this.getJedis().pttl(key);
    }

    @Override
    public String randomKey() {
        return this.getJedis().randomKey();
    }

    @Override
    public String rename(byte[] key, byte[] newKey) {
        return this.getJedis().rename(key, newKey);
    }

    @Override
    public Long renamenx(byte[] key, byte[] newKey) {
        return this.getJedis().renamenx(key, newKey);
    }

    @Override
    public byte[] rpop(byte[] key) {
        return this.getJedis().rpop(key);
    }

    @Override
    public byte[] rpoplpush(byte[] srcKey, byte[] destKey) {
        return this.getJedis().rpoplpush(srcKey, destKey);
    }

    @Override
    public Long rpush(byte[] key, byte[][] values) {
        return this.getJedis().rpush(key, values);
    }

    @Override
    public Long rpushx(byte[] key, byte[] value) {
        return this.getJedis().rpushx(key, value);
    }

    @Override
    public Long sadd(byte[] key, byte[][] values) {
        return this.getJedis().sadd(key, values);
    }

    @Override
    public Long scard(byte[] key) {
        return this.getJedis().scard(key);
    }

    @Override
    public byte[][] sdiff(byte[][] keys) {
        Set<byte[]> sdiff = this.getJedis().sdiff(keys);
        return sdiff.toArray(new byte[sdiff.size()][]);
    }

    @Override
    public Long sdiffstore(byte[] destKey, byte[][] keys) {
        return this.getJedis().sdiffstore(destKey, keys);
    }

    @Override
    public String set(byte[] key, byte[] value) {
        return this.getJedis().set(key, value);
    }

    @Override
    public String setex(byte[] key, Integer seconds, byte[] value) {
        return this.getJedis().setex(key, seconds, value);
    }

    @Override
    public Long setnx(byte[] key, byte[] value) {
        return this.getJedis().setnx(key, value);
    }

    @Override
    public Long setrange(byte[] key, Long offset, byte[] value) {
        return this.getJedis().setrange(key, offset, value);
    }

    @Override
    public byte[][] sinter(byte[][] keys) {
        Set<byte[]> sinter = this.getJedis().sinter(keys);
        return sinter.toArray(new byte[sinter.size()][]);
    }

    @Override
    public Long sinterstore(byte[] destKey, byte[][] keys) {
        return this.getJedis().sinterstore(destKey, keys);
    }

    @Override
    public Boolean sismember(byte[] key, byte[] value) {
        return this.getJedis().sismember(key, value);
    }

    @Override
    public byte[][] smembers(byte[] key) {
        Set<byte[]> smembers = this.getJedis().smembers(key);
        return smembers.toArray(new byte[smembers.size()][]);
    }

    @Override
    public Long smove(byte[] srcKey, byte[] destKey, byte[] value) {
        return this.getJedis().smove(srcKey, destKey, value);
    }

    @Override
    public byte[] spop(byte[] key) {
        return this.getJedis().spop(key);
    }

    @Override
    public byte[][] srandmember(byte[] key, Integer count) {
        if (null == count || 0 == count) {
            return new byte[][] { this.getJedis().srandmember(key) };
        }

        List<byte[]> srandmember = this.getJedis().srandmember(key, count);
        return srandmember.toArray(new byte[srandmember.size()][]);
    }

    @Override
    public Long srem(byte[] key, byte[][] values) {
        return this.getJedis().srem(key, values);
    }

    @Override
    public Long strlen(byte[] key) {
        return this.getJedis().strlen(key);
    }

    @Override
    public byte[][] sunion(byte[][] keys) {
        Set<byte[]> sunion = this.getJedis().sunion(keys);
        return sunion.toArray(new byte[sunion.size()][]);
    }

    @Override
    public Long sunionstore(byte[] destKey, byte[][] keys) {
        return this.getJedis().sunionstore(destKey, keys);
    }

    @Override
    public Long ttl(byte[] key) {
        return this.getJedis().ttl(key);
    }

    @Override
    public String type(byte[] key) {
        return this.getJedis().type(key);
    }

    @Override
    public Long zadd(byte[] key, Map<byte[], Double> members) {
        return this.getJedis().zadd(key, members);
    }

    @Override
    public Long zcard(byte[] key) {
        return this.getJedis().zcard(key);
    }

    @Override
    public Long zcount(byte[] key, Double min, Double max) {
        return this.getJedis().zcount(key, min, max);
    }

    @Override
    public Double zincrby(byte[] key, Double score, byte[] value) {
        return this.getJedis().zincrby(key, score, value);
    }

    @Override
    public Long zlexcount(byte[] key, byte[] min, byte[] max) {
        return this.getJedis().zlexcount(key, min, max);
    }

    @Override
    public Long zrank(byte[] key, byte[] value) {
        return this.getJedis().zrank(key, value);
    }

    @Override
    public Long zrem(byte[] key, byte[][] values) {
        return this.getJedis().zrem(key, values);
    }

    @Override
    public Long zremrangeByRank(byte[] key, Long from, Long to) {
        return this.getJedis().zremrangeByRank(key, from, to);
    }

    @Override
    public Long zremrangeByScore(byte[] key, Double min, Double max) {
        return this.getJedis().zremrangeByScore(key, min, max);
    }

    @Override
    public Long zrevrank(byte[] key, byte[] value) {
        return this.getJedis().zrevrank(key, value);
    }

    @Override
    public Double zscore(byte[] key, byte[] value) {
        return this.getJedis().zscore(key, value);
    }

    @Override
    public Object eval(byte[] script) {
        return this.getJedis().eval(script);
    }

    @Override
    public byte[][] configGet(byte[] pattern) {
        List<byte[]> configGet = this.getJedis().configGet(pattern);
        return configGet.toArray(new byte[configGet.size()][]);
    }

    @Override
    public String toString() {
        return super.toString() //
                + ", port=" + this.getJdbcUrl() //
                + ", jedis=" + this.jedis;
    }
}
